/**
@author		Jong Min, Lee
@date		  10/01/2014
@breif		Dicom study class 

copyright(c) Tae Young Soft. All right reserved. 2014
*/
#include "stdafx.h"
#include "Taurus_DcmData/DcmStudy.h"

#include "Taurus_Util//Errors.h"

#include "Taurus_DcmData/DcmSeries.h"
#include "Taurus_DcmData/IStudyInfo.h"
#include "Taurus_DcmData/ISeriesInfo.h"

CDcmStudy::CDcmStudy()
{
  init();
}

CDcmStudy::~CDcmStudy()
{
  destroy();
}

CDcmSeries* CDcmStudy::findSeries(const TCHAR* key) const
{
  if(key == nullptr) return nullptr;

  CDcmSeries* series = findImageSeries(key);
  if(series != nullptr) return series;

  series = findNoneImageSeries(key);
  return series;
}

CDcmSeries* CDcmStudy::findImageSeries(const TCHAR* key) const
{
  if(key == nullptr) return nullptr;

  unsigned num = m_theImageSeries.size();
  for(unsigned int i = 0; i < num; ++i)
  {
    CDcmSeries* series = m_theImageSeries[i];
    const TCHAR* seriesKey = series->getKey();

    if(_tcscmp(seriesKey, key) == 0) return series;
  }

  return nullptr;
}

CDcmSeries* CDcmStudy::findNoneImageSeries(const TCHAR* key) const
{
  if(key == nullptr) return nullptr;

  unsigned num = m_theNoneImageSeries.size();
  for(unsigned int i = 0; i < num; ++i)
  {
    CDcmSeries* series = m_theNoneImageSeries[i];
    const TCHAR* seriesKey = series->getKey();

    if(_tcscmp(seriesKey, key) == 0) return series;
  }

  return nullptr;
}

DWORD CDcmStudy::addSeries(CDcmSeries* series)
{
  if(series == nullptr) return ERROR_INVALID_PARAMETER;

  _TRY_BEGIN
  if(series->isNoneImage())
    m_theNoneImageSeries.push_back(series);
  else
    m_theImageSeries.push_back(series);
  _CATCH_ALL
  return ERROR_NOT_ENOUGH_MEMORY;
  _CATCH_END

  series->setParent(this);
  return ERROR_SUCCESS;
}

unsigned CDcmStudy::getNumSeries() const
{
  return getNumImageSeries() + getNumNoneImageSeries();
}

unsigned CDcmStudy::getNumImageSeries() const
{
  return m_theImageSeries.size();
}

CDcmSeries* CDcmStudy::getImageSeries(const unsigned int index) const
{
  if(index >= m_theImageSeries.size()) return nullptr;

  return m_theImageSeries[index];
}

unsigned CDcmStudy::getNumNoneImageSeries() const
{
  return m_theNoneImageSeries.size();
}

CDcmSeries* CDcmStudy::getNoneImageSeries(const unsigned int index) const
{
  if(index >= m_theNoneImageSeries.size()) return nullptr;

  return m_theNoneImageSeries[index];
}

DWORD CDcmStudy::removeNoRefSeries()
{
  DWORD errorImage = removeNotRefElemSeries(m_theImageSeries);
  DWORD errorNoneImage = removeNotRefElemSeries(m_theNoneImageSeries);
  if(errorImage != ERROR_SUCCESS) return errorImage;
  if(errorNoneImage != ERROR_SUCCESS) return errorNoneImage;
  return ERROR_SUCCESS;
}

void CDcmStudy::init()
{
  m_theRefCount = 0;
  m_theMedia = DcmStudyMediaFirstInvalid;
  m_theKey = _T("");
}

void CDcmStudy::destroy()
{
  removeAllSeries();
}

void CDcmStudy::removeAllSeries()
{
  removeAllImageSeries();
  removeAllNoneImageSeries();
}

void CDcmStudy::removeAllImageSeries()
{
  unsigned num = m_theImageSeries.size();
  for(unsigned i = 0; i < num; ++i)
    _DELETE(m_theImageSeries[i]);
  m_theImageSeries.clear();
}

void CDcmStudy::removeAllNoneImageSeries()
{
  unsigned num = m_theNoneImageSeries.size();
  for(unsigned i = 0; i < num; ++i)
    _DELETE(m_theNoneImageSeries[i]);
  m_theNoneImageSeries.clear();
}

DWORD CDcmStudy::removeNotRefElemSeries(std::vector<CDcmSeries*>& series)
{
  unsigned int numSeries = series.size();
  CDcmSeries** temp = nullptr;
  _TRY_ALLOC(temp, CDcmSeries*[numSeries])
  if(temp == nullptr) return ERROR_NOT_ENOUGH_MEMORY;

  memcpy(temp, series.data(), sizeof(CDcmSeries*) * numSeries);

  unsigned int numRefSeries = 0;
  for(unsigned int i = 0; i < numSeries; ++i)
  {
    if(series[i]->getRefCount() > 0)
      numRefSeries++;
  }

  _TRY_BEGIN
  series.resize(numRefSeries);
  _CATCH_ALL
  _DELETE_ARR(temp)
  return ERROR_NOT_ENOUGH_MEMORY;
  _CATCH_END

  for(unsigned int i = 0, k = 0; i < numSeries && k < numRefSeries; ++i)
  {
    if(temp[i]->getRefCount() > 0)
    {
      series[k++] = temp[i];
      temp[i] = nullptr;
    }
  }
  for(unsigned int i = 0; i < numRefSeries; ++i)
  {
    _DELETE(temp[i]);
  }
  _DELETE_ARR(temp);
  return ERROR_SUCCESS;
}


DWORD CDcmStudyProducer::produce(IStudyInfo& studyInfo, 
                                 DcmStudyMedia media, 
                                 CDcmStudy*& outStudy)
{
  if(media <= DcmStudyMediaFirstInvalid ||
     media >= DcmStudyMediaLastInvalid)
     return ERROR_INVALID_PARAMETER;

  CDcmStudy* newStudy = nullptr;
  _TRY_ALLOC(newStudy, CDcmStudy);
  if(newStudy == nullptr) return ERROR_NOT_ENOUGH_MEMORY;

  DWORD error = ERROR_SUCCESS;

  newStudy->m_theMedia = media;
  newStudy->m_theKey = studyInfo.getKey();

  //create dcm series
  int numSeriesInfo = studyInfo.getNumSeriesInfo();
  for(int i = 0; i < numSeriesInfo; i++)
  {
    ISeriesInfo* seriesInfo = studyInfo.getSeriesInfo(i);
    if(seriesInfo == nullptr) continue;

    CDcmSeries* newSeries = nullptr;
    error = CDcmSeriesProducer::produce(*seriesInfo,
                                        newStudy,
                                        newSeries);
    if(error != ERROR_SUCCESS)
    {
      _DELETE(newSeries);
      _DELETE(newStudy);
      return error;
    }

    error = newStudy->addSeries(newSeries);
    if(error != ERROR_SUCCESS)
    {
      _DELETE(newSeries);
      _DELETE(newStudy);
      return error;
    }
  }

  if(newStudy->getNumSeries() == 0 || newStudy->getNumImageSeries() == 0)
  {
    _DELETE(newStudy);
    return ERROR_INVALID_STUDY_INFO;
  }

  outStudy = newStudy;
  return ERROR_SUCCESS;
}


